package de.jmda.sample.xml;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.xml.bind.annotation.XmlRootElement;

import de.jmda.mproc.LaunchConfiguration;
import de.jmda.mproc.Launcher;
import de.jmda.mproc.Processor;
import de.jmda.util.fileset.FileSet.RuleSetUpdateMode;
import de.jmda.util.fileset.FileSetJavaFilesOnly;

@SupportedAnnotationTypes(value = {"javax.xml.bind.annotation.XmlRootElement"})
@SupportedSourceVersion(value = SourceVersion.RELEASE_7)
public class XMLRootElementProcessor
		extends Processor
{
	/**
	 * stores type elements annotated with <code>XmlRootElement</code>
	 */
	private Set<TypeElement> typeElements = new HashSet<TypeElement>();

	@Override
	protected boolean process()
	{
		if (roundEnvironment.processingOver() == false)
		{
			for (Element element :
			     roundEnvironment.getElementsAnnotatedWith(XmlRootElement.class))
			{
				if (element instanceof TypeElement)
				{
					typeElements.add((TypeElement) element);
				}
			}
		}
		return false;
	}

	/**
	 * @see de.jmda.mproc.Processor#getSupposedSupportedAnnotationTypes()
	 */
	@Override
	protected Class<?>[] getSupposedSupportedAnnotationTypes()
	{
    return new Class<?>[] { XmlRootElement.class };
	}

	/**
	 * Reads all types in directory <code>sourceRoot</code> and its subdirectories
	 * and returns a set containing type elements for each type annotated with
	 * <code>XMLRootElement</code>.
	 *
	 * @param sourceRoot
	 * @return
	 */
	public static Set<TypeElement> process(File sourceRoot)
	{
		FileSetJavaFilesOnly fileSetJavaFilesOnly = new FileSetJavaFilesOnly();

		fileSetJavaFilesOnly.includeDirectoryRecursive(
				sourceRoot, RuleSetUpdateMode.ADD_RULE);
		
		XMLRootElementProcessor xmlRootElementProcessor =
				new XMLRootElementProcessor();
		
		LaunchConfiguration launchConfiguration = new LaunchConfiguration();

		launchConfiguration.files.addAll(fileSetJavaFilesOnly.calculateFileSet());
		launchConfiguration.processors.add(xmlRootElementProcessor);

		try
    {
      Launcher.launch(launchConfiguration);
    }
    catch (IOException e)
    {
    	throw new ExceptionInInitializerError(
    			"failure launching configuration\n" + e);
    }

		return xmlRootElementProcessor.typeElements;
	}

	public static void main(String[] args)
  {
		process(getSourceRoot());
  }

	/**
	 * @return root directory containing annotated source files
	 */
	private static File getSourceRoot()
	{
		File result = new File("./src/main/java");

		if (result.exists() == false)
		{
			throw new ExceptionInInitializerError(
					result.getAbsolutePath() + " does not exist");
		}
		else if (result.isDirectory() == false)
		{
			throw new ExceptionInInitializerError(
					result.getAbsolutePath() + " is not a directory");
		}

		return result;
	}
}